package com.lagou.edu.container;

import com.lagou.edu.utils.MiniAppClassLoader;
import com.minicat.servlet.Servlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * servlet解析器
 *
 * @author liangzj
 * @date 2021/3/28 17:41
 */
public class WebXmlResolver {

    private ClassLoader classLoader;

    private Context context;

    public WebXmlResolver(ClassLoader classLoader, Context context) {
        this.classLoader = classLoader;
        this.context = context;
    }

    public void loadServlets(InputStream webConfigInputStream) {
        SAXReader saxReader = new SAXReader();

        try {
            Document webConfigDoc = saxReader.read(webConfigInputStream);
            Element rootElement = webConfigDoc.getRootElement();

            List<Element> servletElements = rootElement.selectNodes("//servlet");
            // 加载wrapper
            loadWrappers(rootElement, servletElements);
            // 实例化servlet
            instanceServlet(classLoader);

        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * 实例化servlet对象
     *
     * @param classLoader
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private void instanceServlet(ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        for (Wrapper wrapper : context.getWrappers()) {
            Object o = classLoader.loadClass(wrapper.getServletClassName()).getDeclaredConstructor().newInstance();
            wrapper.setServlet((Servlet) o);
        }
    }

    /**
     * 注册servlet信息
     *
     * @param rootElement
     * @param servletElements
     */
    private void loadWrappers(Element rootElement, List<Element> servletElements) {
        for (int i = 0; i < servletElements.size(); i++) {
            Element servletElement = servletElements.get(i);
            resolveWrapper(servletElement, rootElement);
        }
    }

    /**
     * 解析servlet
     *
     * @param servletElement
     */
    private void resolveWrapper(Element servletElement, Element rootElement) {
        // 获取servlet名称
        Element servletNameElement = (Element) servletElement.selectSingleNode("servlet-name");
        String servletName = servletNameElement.getStringValue();
        // 获取servlet类全限定名
        Element servletClassElement = (Element) servletElement.selectSingleNode("servlet-class");
        String servletClass = servletClassElement.getStringValue();
        // 获取对应的url
        String xpathExpression = String.format("/web-app/servlet-mapping[servlet-name='%s']", servletName);
        List<Element> servletMappings = rootElement.selectNodes(xpathExpression);
        List<String> urlPatterns = servletMappings.stream()
                .map(servletMapping -> servletMapping.selectSingleNode("url-pattern").getStringValue())
                .collect(Collectors.toList());
        // 记录servlet信息
        Wrapper wrapper = new Wrapper(servletName, servletClass, urlPatterns);

        context.addWrapper(wrapper);
    }

    public static void main(String[] args) {
        try {
            MiniAppClassLoader miniAppClassLoader = new MiniAppClassLoader("E:\\produce\\IdeaProjects\\minicat\\demo1\\target\\classes\\");
            Class<?> aClass = miniAppClassLoader.loadClass("com.demo1.servlet.HelloServlet");
            System.out.println(aClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
